package com.jonah.sqlsession;

import com.jonah.executor.SimpleExecutor;
import com.jonah.pojo.Configuration;
import com.jonah.pojo.MappedStatement;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.List;

/**
 * @Author: Jonah.Chen
 * @Date: 2020/8/5 22:37
 * @Description:
 */
public class DefaultSqlSession implements SqlSession {

    private Configuration configuration;

    public DefaultSqlSession(Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    public <T> List<T> selectList(String statementId, Object... params) throws Exception {
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
        List<Object> objects = new SimpleExecutor().query(configuration, mappedStatement, params);
        return (List<T>) objects;
    }

    @Override
    public <T> T selectOne(String statementId, Object... params) throws Exception {
        List<Object> objectList = selectList(statementId, params);
        if (objectList.size() == 1) {
            return (T) objectList.get(0);
        } else {
            throw new RuntimeException("返回结果过多");
        }
    }

    @Override
    public Integer insertOne(String statementid, Object param) throws Exception {
        MappedStatement mappedStatement = this.configuration.getMappedStatementMap().get(statementid);
        return new SimpleExecutor().update(this.configuration, mappedStatement, param);
    }

    @Override
    public Integer updateOne(String statementid, Object param) throws Exception {
        MappedStatement mappedStatement = this.configuration.getMappedStatementMap().get(statementid);
        return new SimpleExecutor().update(this.configuration, mappedStatement, param);
    }

    @Override
    public Integer deleteOne(String statementid, Object param) throws Exception {
        MappedStatement mappedStatement = this.configuration.getMappedStatementMap().get(statementid);
        return new SimpleExecutor().update(this.configuration, mappedStatement, param);
    }


    @Override
    public <T> T getMapper(Class<?> mapperClz) {
        // 使用JDK动态代理, 为DAO接口生成代理对象, 并返回
        Object instance = Proxy.newProxyInstance(
                DefaultSqlSession.class.getClassLoader(),
                new Class[]{mapperClz}, (proxy, method, args) -> {
                    // 底层还是执行JDBC方法, 根据不同情况来调用不同方法
                    // 1.准备参数 statementId(接口全限定名.方法名), param(args)
                    String className = method.getDeclaringClass().getName();
                    String methodName = method.getName();
                    String statementId = className.concat(".").concat(methodName);
                    // 2.调用方法 需要判断当前调用方法的返回值
                    // 获取当前调用方法的返回值类型
                    if (methodName.contains("select")) {
                        Type returnType = method.getGenericReturnType();
                        // 判断是否进行了"泛型类型参数化"(就是判断当前的类型是否有泛型)
                        if (returnType instanceof ParameterizedType) {
                            List<Object> objects = selectList(statementId, args);
                            return objects;
                        }
                        return selectOne(statementId, args);
                    } else if (methodName.contains("insert")) {
                        return insertOne(statementId, args[0]);
                    } else if (methodName.contains("update")) {
                        return updateOne(statementId, args[0]);
                    } else if (methodName.contains("delete")) {
                        return deleteOne(statementId, args[0]);
                    } else {
                        throw new RuntimeException("不支持命名");
                    }
                });
        return (T) instance;
    }
}